#ifdef KITSCHY_DEBUG_MEMORY 
#include "debug_memorymanager.h"
#endif

#ifdef WIN32
#include "windows.h"
#endif

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "math.h"
#include "pthread.h"

#include "BList.h"
#include "BVector.h"
#include "geometrics.h"
#include "quaternion.h"
#include "symbol.h"
#include "sort.h"
#include "ontology.h"
#include "featureterm.h"
#include "FTKBase.h"

#include "AWEntity.h"
#include "AWMessage.h"
#include "AWBrain.h"
#include "AWTracerBrain.h"
#include "AWThreadedBrain.h"
#include "AWNOOSBrain.h"
#include "AWNOOSLearnerBrain.h"
#include "AWNOOSLearnerBrainSocial.h"

#include "CaseBaseUtils.h"

#include "psm.h"

#include "loader.h"



AW_NOOSLearnerBrainSocial::AW_NOOSLearnerBrainSocial(Ontology *O,FTKBase *Memory,FTKBase *CB,bool pause) : AW_NOOSLearnerBrain(O,Memory,CB,pause) 
{
	class_name->set("AW_NOOSLearnerBrainSocial");

	bet_solution=0;
	bet_amount=0;
	money=1000.0f;

	m_ontology->new_sort("problem-prediction-bet","problem-prediction",1,"bet","float");
	m_ontology->new_sort("money-gain-inform-message","any",1,"money","float");

} /* AWNOOSLearnerBrainSocial::AWNOOSLearnerBrainSocial */ 



AW_NOOSLearnerBrainSocial::AW_NOOSLearnerBrainSocial(FILE *fp,Ontology *O,FTKBase *Memory,FTKBase *CB,bool pause) : AW_NOOSLearnerBrain(O,Memory,CB,pause) 
{
	class_name->set("AWNOOSLearnerBrainSocial");

	bet_solution=0;
	bet_amount=0;
	money=1000.0f;

	m_ontology->new_sort("problem-prediction-bet","problem-prediction",1,"bet","float");
	m_ontology->new_sort("money-gain-inform-message","any",1,"money","float");

	load(fp);
} /* AW_NOOSLearnerBrain::AW_NOOSLearnerBrain */ 


AW_NOOSLearnerBrainSocial::~AW_NOOSLearnerBrainSocial()
{
	if (bet_solution!=0) delete bet_solution;

} /* AW_NOOSLearnerBrainSocial::~AW_NOOSLearnerBrainSocial */ 


bool AW_NOOSLearnerBrainSocial::load(FILE *fp) 
{
	if (!AW_NOOSLearnerBrain::load(fp)) return false;

	{
		int i,n_friends=0;
		Symbol *f;

		if (1!=fscanf(fp,"%i",&n_friends)) return false;

		for(i=0;i<n_friends;i++) {
			f=new Symbol(fp);
			m_friends.Add(f);
		} // if

		if (1!=fscanf(fp,"%f",&money)) return false;
	}

	return true;
} /* AW_NOOSLearnerBrainSocial::load */ 


bool AW_NOOSLearnerBrainSocial::save(FILE *fp) 
{
	if (!AW_NOOSLearnerBrain::save(fp)) return false;

	{
		Symbol *f;
		fprintf(fp,"%i\n",m_friends.Length());

		m_friends.Rewind();
		while(m_friends.Iterate(f)) f->save(fp);
	}

	fprintf(fp,"%f\n",money);

	return true;
} /* AW_NOOSLearnerBrainSocial::save */ 


bool AW_NOOSLearnerBrainSocial::is_a(char *c)
{
	if (strcmp(c,"AW_NOOSLearnerBrainSocial")==0) return true;

	return AW_NOOSLearnerBrain::is_a(c);
} /* AW_NOOSLearnerBrainSocial::is_a */ 


bool AW_NOOSLearnerBrainSocial::is_a(Symbol *c)
{
	if (c->cmp("AW_NOOSLearnerBrainSocial")) return true;

	return AW_NOOSLearnerBrain::is_a(c);
} /* AW_NOOSLearnerBrainSocial::is_a */ 


List<Symbol> *AW_NOOSLearnerBrainSocial::get_friends(void)
{
	List<Symbol> *l=new List<Symbol>;
	l->Copy(m_friends);
	return l;
} /* AW_NOOSLearnerBrainSocial::get_friends */ 


bool AW_NOOSLearnerBrainSocial::process_message(AW_Message *m,FeatureTerm *content)
{	
	Symbol *my_name;
	my_name=m->receiver;

	// request-prediction-message ---------------------------------------------------------------------
	if (content->getSort()==m_ontology->get_sort("request-prediction-message") ||
		content->getSort()==m_ontology->get_sort("request-test-prediction-message")) {
		bool test=false;
		FeatureTerm *op;
		FeatureTerm *problem;
		FeatureTerm *answer;
		char *s;
		Symbol *cs=m_collaboration_strategy;

		{
			FeatureTerm *f;
			f=content->featureValue("strategy");
			if (f!=0 && f->isSymbol()) cs=f->getSymbol();
			delete f;
		}

		if (cs->cmp("social")) {

			if (content->getSort()==m_ontology->get_sort("request-test-prediction-message")) test=true;

			{
				/* Set the color of the agent to "working": */ 
				FeatureTerm *op;
				op=FeatureTerm::fromStringNOOS("(define (color-operator) (r 1.0) (g 0.4) (b 0.4))",m_memory,m_ontology);
				enqueue_operator(op);
			}

			problem=content->featureValue("problem");
			if (last_problem_solved!=0) delete last_problem_solved;
			last_problem_solved=new FeatureTerm(problem);

			{
				Sort *sort=get_case_sort(m_ontology,problem->getSort());

				/* Solve the problem: */ 
				answer=0;
				answer = solve_problem_social(problem,sort,my_name,test);

//				if (answer==0) answer = solve_problem_individually(problem,sort,my_name);
				if (answer==0) {
					s=new char[15];
					strcpy(s,"(define (any))");
				} else {
					s=answer->toStringNOOS(m_memory);
					delete answer;
				} /* if */ 
			}

			cs=0;

			/* Send back the solution: */ 
			op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
							   "receiver",new FeatureTerm(0,new Symbol(m->sender),m_ontology),
							   "content",new FeatureTerm(0,new Symbol(s),m_ontology));
			enqueue_operator(op);
			delete []s;

			delete problem;
			return true;
		} // if
	} /* if */ 	


	// solution-inform-message ---------------------------------------------------------------------
	if (content->getSort()==m_ontology->get_sort("money-gain-inform-message")) {
		FeatureTerm *m_ft=content->featureValue("money"),*op;
		float money_increase = m_ft->getFloat();

		money+=money_increase;

		write_debug_report("[%s] I won %g, now I have %g.\n",my_name->get(),money_increase,money);	
		
		/* Send back a confirmation: */ 
		op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
						   "receiver",new FeatureTerm(0,new Symbol(m->sender),m_ontology),
						   "content",new FeatureTerm(0,new Symbol("(define (any))"),m_ontology));
		enqueue_operator(op);

		return true;
	} // if 


	return AW_NOOSLearnerBrain::process_message(m,content);
} /* AW_NOOSLearnerBrainSocial::process_message */ 



FeatureTerm *AW_NOOSLearnerBrainSocial::solve_problem_social(FeatureTerm *problem,Sort *sort,Symbol *my_name,bool test)
{
	FeatureTerm *current_JER = 0, *new_JER = 0, *solution_record;
	List<Symbol> *agent_names=get_friends(),*l;
	Symbol *agent_name;

	write_debug_report("[%s] solve_problem_social: started.\n",my_name->get());

	// Argue one by one with each of the friends:
	/* Retrieve the set of other agents: */ 

	current_JER=build_single_jer(problem,sort,my_name);

	agent_names=get_friends();
	agent_names->Rewind();
	while(agent_names->Iterate(agent_name)) {
		write_debug_report("[%s] solve_problem_social: talking with %s.\n",my_name->get(),agent_name->get());
	
		l = new List<Symbol>;
		l->Add(new Symbol(agent_name));
		new_JER = solve_problem_IBA_convener_social(problem,sort,my_name,test,l,current_JER);
		delete l;
		if (current_JER!=0) delete current_JER;
		current_JER=new_JER;
		current_JER->defineFeatureValue("agent",new FeatureTerm(0,new Symbol(my_name),m_ontology));
	} // while 
	delete agent_names;

	if (current_JER==0) return 0;

	if (test) {
		float bet = 100.0f*local_confidence(current_JER,get_case_sort(m_ontology,problem->getSort()));
		write_debug_report("[%s] I bet %g.\n",my_name->get(),bet);		
		solution_record=new FeatureTerm((char *)0,m_ontology->get_sort("problem-prediction-bet"),2,
										"solution",current_JER->featureValue("solution"),
										"bet",new FeatureTerm((Symbol *)0,bet,m_ontology));
	} else {
		float bet = 100.0f*local_confidence(current_JER,get_case_sort(m_ontology,problem->getSort()));
		money-=bet;
		write_debug_report("[%s] I bet %g, now I have %g.\n",my_name->get(),bet,money);		
		solution_record=new FeatureTerm((char *)0,m_ontology->get_sort("problem-prediction-bet"),2,
										"solution",current_JER->featureValue("solution"),
										"bet",new FeatureTerm((Symbol *)0,bet,m_ontology));
	} // if
	delete current_JER;

	return solution_record;
} /* AW_NOOSLearnerBrainSocial::solve_problem_social */ 



FeatureTerm *AW_NOOSLearnerBrainSocial::solve_problem_IBA_convener_social(FeatureTerm *problem,Sort *sort,Symbol *my_name,bool test,List<Symbol> *others,FeatureTerm *initial_JER)
{
	int i;
	char *str;
	AW_Message *m;
	Symbol *agent_name;
	List<Symbol> agent_names;
	FeatureTerm *my_prediction,*prediction,*JER,*f,*op;
	List<FeatureTerm> JERs;
	List<FeatureTerm> new_JERs;
	List<float> JER_Cs;
	List<FeatureTerm> self_CAs_historic,self_CEs_historic;
	int current_round;

	write_debug_report("[%s](C): IBA convener started.\n",my_name->get());

	/* Retrieve the set of other agents: */ 
	agent_names.Copy(*others);

	/* Make the other agents to start their IBA-other methods: */ 
	agent_names.Rewind();
	while(agent_names.Iterate(agent_name)) {
		f=new FeatureTerm((char *)0,m_ontology->get_sort("request-iba-collaboration-message"),1,
						  "problem",new FeatureTerm(problem));

		str=f->toStringNOOS(m_memory);
		op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
						   "receiver",new FeatureTerm(0,new Symbol(agent_name),m_ontology),
						   "content",new FeatureTerm(0,new Symbol(str),m_ontology));
		delete []str;
		delete f;
		enqueue_operator(op);
	} /* while */ 

	/* Solve the problem individually: */ 
	if (initial_JER==0) {
		my_prediction=build_single_jer(problem,sort,my_name);
	} else {
		my_prediction=new FeatureTerm(initial_JER);
	} // if 
	JERs.Insert(my_prediction);

	/* Receive the solution from the others: */ 
	for(i=0;i<agent_names.Length();i++) {
		wait_message();
		m=get_message();
		prediction=FeatureTerm::fromStringNOOS(m->content->get(),m_memory,m_ontology);
		JERs.Add(prediction);
		delete m;
	} /* for */ 

	/* Compute the confidence of the arguments: */ 
	IBA_compute_confidence(problem,&JERs,&JER_Cs,&agent_names);

	/* Show initial arguments: */ 
	current_round=0;
	{
		int i;
		FeatureTerm *f,*f2;
		char *s,*s2;

		write_debug_report("JERs in round %i\n",current_round);
		i=0;
		JERs.Rewind();
		while(JERs.Iterate(prediction)) {
			f=prediction->featureValueQuick("solution");
			f2=prediction->featureValueQuick("agent");
			s2=f->toStringNOOS(m_memory);
			write_debug_report("JER %i (%s), for solution %s\n",i,f2->getSymbol()->get(),s2);
			delete []s2;
			f=prediction->featureValueQuick("justification");
			s=f->toStringNOOS(m_memory);
			write_debug_report("%s\n",s);
			delete []s;
			i++;
		} /* while */ 
	}

	/* Start the IBA protocol: */ 
	{
		bool any_change=false;
		do {
			any_change=false;
			write_debug_report("[%s](C): Round %i of the IBA protocol starts.\n",my_name->get(),current_round);

			/* Pass the token: */ 
			agent_names.Rewind();
			while(agent_names.Iterate(agent_name)) {
				{
					FeatureTerm *JER;
					float *c;
					FeatureTerm *f2=FeatureTerm::SetFeatureTerm((Symbol *)0);

					JERs.Rewind();
					JER_Cs.Rewind();
					while(JERs.Iterate(JER) && JER_Cs.Iterate(c)) {
						f=new FeatureTerm((char *)0,m_ontology->get_sort("iba-prediction-confidence"),2,
																		 "prediction",new FeatureTerm(JER),
																		 "confidence",new FeatureTerm((Symbol *)0,*c,m_ontology));					
						f2->addSetValue(f);
					} /* while */ 

					f=new FeatureTerm((char *)0,m_ontology->get_sort("token-iba-message"),1,
									  "arguments",f2);
				}

				str=f->toStringNOOS(m_memory);
				op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
								   "receiver",new FeatureTerm(0,new Symbol(agent_name),m_ontology),
								   "content",new FeatureTerm(0,new Symbol(str),m_ontology));
				delete []str;
				delete f;
				enqueue_operator(op);

				/* Wait till the agent finishes: */ 
				wait_message();
				m=get_message();
				{
					FeatureTerm *tmp=0,*counterargument=0;
					List<FeatureTerm> arguments;

					if (m->content->get()!=0) {
						tmp=FeatureTerm::fromStringNOOS(m->content->get(),m_memory,m_ontology);
					} /* if */ 

					if (tmp!=0) {
						any_change=true;

						if (tmp->isSet()) {
							List<FeatureTerm> l;
							l.Instance(*tmp->set_values_quick());
							l.Rewind();
							while(l.Iterate(counterargument)) arguments.Add(counterargument);
						} else {
							arguments.Add(tmp);
						} /* if */ 

						while(!arguments.EmptyP()) {
							counterargument=arguments.ExtractIni();

							/* Process counterarguments: */ 
							if (counterargument->getSort()==m_ontology->get_sort("problem-prediction")) {
								/* Substitute the agent's current prediction, and reevaluate its confidence: */ 
								new_JERs.Add(new FeatureTerm(counterargument));
							} /* if */ 

							if (counterargument->getSort()==m_ontology->get_sort("counterargument-message") ||
								counterargument->getSort()==m_ontology->get_sort("counterexample-message")) {
								AW_Message *m2;
								/* Send the counterargument to the appropriate agent: */ 
								/* request him for another prediction, and reevaluate its confidence */ 
								str=counterargument->toStringNOOS(m_memory);
								write_debug_report("[%s](C): Counterargument/example sent to %s.\n",my_name->get(),counterargument->featureValueQuick("agent")->getSymbol()->get());
								if (!counterargument->featureValueQuick("agent")->getSymbol()->cmp(my_name)) {
									op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
													   "receiver",counterargument->featureValue("agent"),
													   "content",new FeatureTerm(0,new Symbol(str),m_ontology));
									delete []str;
									enqueue_operator(op);

									/* Wait till the agent finishes: */ 
									wait_message();
									m2=get_message();
									{
										write_debug_report("[%s](C): Reply received from %s.\n",my_name->get(),m2->sender->get());

										/* If there is a new prediction, add it to the "new_JERs" list: */ 
										FeatureTerm *tmp=0;
		
										if (m2->content->get()!=0) {
											tmp=FeatureTerm::fromStringNOOS(m2->content->get(),m_memory,m_ontology);
										} /* if */ 

										if (tmp!=0) {
											if (tmp->getSort()==m_ontology->get_sort("problem-prediction")) {
												/* Substitute the agent's current prediction, and reevaluate its confidence: */ 
												new_JERs.Add(new FeatureTerm(tmp));
											} /* if */ 
											delete tmp;
										} /* if */ 

									}
									delete m2;
								} else {
									/* The counterargument goes for me (the convener agent): */ 

									/* Receives a counterargument: */ 
									if (counterargument->getSort()==m_ontology->get_sort("counterargument-message")) {
										write_debug_report("[%s](C): received a counterargument.\n",my_name->get());	

										/* Consider whether to change my prediction: */ 
										if (local_confidence(counterargument->featureValueQuick("counterargument"),sort) > 
											local_confidence(my_prediction,sort)) {

											write_debug_report("[%s](C): The counterargument of the other agent has convinced me.\n",my_name->get());
											
											/* change my current prediction: */ 
											my_prediction=counterargument->featureValue("counterargument");
											new_JERs.Add(my_prediction);
										} /* if */ 
									} /* if */ 

									/* Receives a counterexample: */ 
									if (counterargument->getSort()==m_ontology->get_sort("counterexample-message")) {
										FeatureTerm *tmp;

										write_debug_report("[%s](C): received a counterexample.\n",my_name->get());	
										
										/* Retain the new case: */ 
										tmp=counterargument->featureValue("counterexample");
										write_debug_report("[%s](C): learnt case %s\n",m->receiver->get(),tmp->getName()->get());
										received_cases_IBA2A.Add(tmp);

										/* Generate a new prediction: */ 
										{
											FeatureTerm *old_prediction = my_prediction;
											Sort *sort=get_case_sort(m_ontology,problem->getSort());

											my_prediction = build_single_jer(problem,sort,my_name);
											new_JERs.Add(my_prediction);


											/* Check if anyone has changed opinion, for logging purposes: */ 
											{
												FeatureTerm *old_sol,*new_sol;
												old_sol=old_prediction->featureValueQuick("solution");
												new_sol=my_prediction->featureValueQuick("solution");

												if (!(*old_sol==*new_sol)) {
													char *s1,*s2;
													s1=old_prediction->featureValueQuick("solution")->toStringNOOS(m_memory);
													s2=my_prediction->featureValueQuick("solution")->toStringNOOS(m_memory);
													write_debug_report("[%s](C): I changed my mind because of a counterexample (%s to %s).\n",
																		my_name->get(),
																		s1,s2);
													delete []s1;
													delete []s2;
												} // if 
											}

										}
									} /* if */ 
							
								} /* if */ 
							} /* if */ 										
						} /* while */ 

						delete tmp;
						tmp=0;
					} /* if */ 
				}
				delete m;

				/* If any new predictions, compute their global confidence: */ 
				if (!new_JERs.EmptyP()) {
					List<float> new_JER_Cs;
					IBA_compute_confidence(problem,&new_JERs,&new_JER_Cs,&agent_names);
					FeatureTerm *new_JER;
					float *new_C,*old_C;
					int i,pos;
	
					write_debug_report("[%s](C): %i new predictions in this round, reevaluating them.\n",my_name->get(),new_JERs.Length());

					/* substitute the old predictions with the new ones: */ 
					while(!new_JERs.EmptyP()) {
						new_JER=new_JERs.ExtractIni();
						new_C=new_JER_Cs.ExtractIni();

						JERs.Rewind();
						pos=-1;
						i=0;
						while(JERs.Iterate(JER) && pos==-1) {
							if (JER->featureValueQuick("agent")->getSymbol()->cmp(new_JER->featureValueQuick("agent")->getSymbol())) {
								pos=i;
							} /* if */ 
							i++;
						} /* while */ 

						JER=JERs[pos];
						old_C=JER_Cs[pos];
						JERs.SetObj(pos,new_JER);
						JER_Cs.SetObj(pos,new_C);
						if (my_prediction==JER) my_prediction=new_JER;

						/* Check if anyone has changed opinion, for logging purposes: */ 
						{
							FeatureTerm *old_sol,*new_sol;
							old_sol=JER->featureValueQuick("solution");
							new_sol=new_JER->featureValueQuick("solution");

							if (!(*old_sol==*new_sol)) {
								char *s1,*s2;
								s1=JER->featureValueQuick("solution")->toStringNOOS(m_memory);
								s2=new_JER->featureValueQuick("solution")->toStringNOOS(m_memory);
								write_debug_report("[%s](C): Agent %s has changed its mind (%s to %s).\n",
													my_name->get(),
													JER->featureValueQuick("agent")->getSymbol()->get(),
													s1,s2);
								delete []s1;
								delete []s2;
							} // if 
						}

						delete JER;
						delete old_C;

					} /* while */ 
				} /* if */ 

			} /* while */ 

			/* Personally own the token: */ 
			write_debug_report("[%s](C): I have the token -----------------------------------\n",my_name->get());
			{
				/* Prepare all the messages I want to send: */ 
				FeatureTerm *counterargument;

				counterargument=IBA_generate_counterargument(problem,&JERs,&JER_Cs,my_name,&self_CAs_historic,&self_CEs_historic);
				if (counterargument!=0) {
					any_change=true;

					/* If it is a counterargument, then consider if changing my current prediction: */ 
					if (counterargument->getSort()==m_ontology->get_sort("counterargument-message")) {
						if (local_confidence(counterargument->featureValueQuick("counterargument"),sort) > 
							local_confidence(my_prediction,sort)) {
							/* change my current prediction: */ 
							write_debug_report("[%s](C): I change my current prediction.\n",my_name->get());
							my_prediction=counterargument->featureValue("counterargument");
							new_JERs.Add(my_prediction);
						} /* if */ 
					} /* if */ 


					if (counterargument->getSort()==m_ontology->get_sort("counterargument-message") ||
						counterargument->getSort()==m_ontology->get_sort("counterexample-message")) {
						AW_Message *m2;
						/* Send the counterargument to the appropriate agent: */ 
						/* request him for another prediction, and reevaluate its confidence */ 
						str=counterargument->toStringNOOS(m_memory);
						write_debug_report("[%s](C): Counterargument/example sent to %s.\n",my_name->get(),counterargument->featureValueQuick("agent")->getSymbol()->get());
						op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
										   "receiver",counterargument->featureValue("agent"),
										   "content",new FeatureTerm(0,new Symbol(str),m_ontology));
						delete []str;
						enqueue_operator(op);

						/* Wait till the agent finishes: */ 
						wait_message();
						m2=get_message();
						{
							write_debug_report("[%s](C): Reply received from %s.\n",my_name->get(),m2->sender->get());

							/* If there is a new prediction, add it to the "new_JERs" list: */ 
							FeatureTerm *tmp=0;

							if (m2->content->get()!=0) {
								tmp=FeatureTerm::fromStringNOOS(m2->content->get(),m_memory,m_ontology);
							} /* if */ 

							if (tmp!=0) {
								if (tmp->getSort()==m_ontology->get_sort("problem-prediction")) {
									/* Substitute the agent's current prediction, and reevaluate its confidence: */ 
									new_JERs.Add(new FeatureTerm(tmp));
								} /* if */ 
								delete tmp;
							} /* if */ 

						}
						delete m2;
					} /* if */ 	

					delete counterargument;
					counterargument=0;
				} /* if */ 

				/* If any new predictions, compute their global confidence: */ 
				if (!new_JERs.EmptyP()) {
					List<float> new_JER_Cs;
					IBA_compute_confidence(problem,&new_JERs,&new_JER_Cs,&agent_names);
					FeatureTerm *new_JER;
					float *new_C,*old_C;
					int i,pos;

					write_debug_report("[%s](C): %i new predictions in this round, reevaluating them.\n",my_name->get(),new_JERs.Length());

					/* substitute the old predictions with the new ones: */ 
					while(!new_JERs.EmptyP()) {
						new_JER=new_JERs.ExtractIni();
						new_C=new_JER_Cs.ExtractIni();

						JERs.Rewind();
						pos=-1;
						i=0;
						while(JERs.Iterate(JER) && pos==-1) {
							if (JER->featureValueQuick("agent")->getSymbol()->cmp(new_JER->featureValueQuick("agent")->getSymbol())) {
								pos=i;
							} /* if */ 
							i++;
						} /* while */ 

						JER=JERs[pos];
						old_C=JER_Cs[pos];
						JERs.SetObj(pos,new_JER);
						JER_Cs.SetObj(pos,new_C);
						if (my_prediction==JER) my_prediction=new_JER;

						/* Check if anyone has changed opinion, for logging purposes: */ 
						{
							FeatureTerm *old_sol,*new_sol;
							old_sol=JER->featureValueQuick("solution");
							new_sol=new_JER->featureValueQuick("solution");

							if (!(*old_sol==*new_sol)) {
								char *s1,*s2;
								s1=JER->featureValueQuick("solution")->toStringNOOS(m_memory);
								s2=new_JER->featureValueQuick("solution")->toStringNOOS(m_memory);
								write_debug_report("[%s](C): Agent %s has changed its mind (%s to %s).\n",
													my_name->get(),
													JER->featureValueQuick("agent")->getSymbol()->get(),
													s1,s2);
								delete []s1;
								delete []s2;
							} // if 
						}

						delete JER;
						delete old_C;

					} /* while */ 
				} /* if */ 
			}

			current_round++;
		}while(any_change);
	}


	/* Inform the other agents that the protocol is over: */ 
	write_debug_report("[%s](C): Sending termination messages to the other agents.\n",my_name->get());
	agent_names.Rewind();
	while(agent_names.Iterate(agent_name)) {
		if (test) f=new FeatureTerm((char *)0,m_ontology->get_sort("reset-test-iba"),0);
			 else f=new FeatureTerm((char *)0,m_ontology->get_sort("reset-iba"),0);

		str=f->toStringNOOS(m_memory);
		op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
						   "receiver",new FeatureTerm(0,new Symbol(agent_name),m_ontology),
						   "content",new FeatureTerm(0,new Symbol(str),m_ontology));
		delete []str;
		delete f;
		enqueue_operator(op);
	} /* while */ 
	for(i=0;i<agent_names.Length();i++) {
		wait_message();
		m=get_message();
		delete m;
	} /* for */ 

	/* Apply retention strategy: */ 
	if (!test) retain_cases(&received_cases_IBA2A,m_amal2_retention_strategy);
	received_cases_IBA2A.Delete();

	/* Decide final solution: */ 
	/*
	write_debug_report("[%s](C): Deciding final solution.\n",my_name->get());
	{
		int pos;
		FeatureTerm *solution_record;
		List<FeatureTerm> solutions;
		List<float> votes;
		FeatureTerm *solution;
		int selected;

		for(i=0;i<JERs.Length();i++) {
			solution=JERs[i]->featureValueQuick("solution");
			pos=solutions.Position(solution);
			if (pos==-1) {
				solutions.Add(new FeatureTerm(solution));
				votes.Add(new float(*JER_Cs[i]));
			} else {
				*votes[pos]=*votes[pos]+*JER_Cs[i];
			} // if 
		} // for  

		for(i=0;i<solutions.Length();i++) {
			char *s;
			s=solutions[i]->toStringNOOS(m_memory);
			write_debug_report("%s -> %g\n",s,*votes[i]);
			delete []s;
		} // for  

		selected=0;
		for(i=0;i<solutions.Length();i++) {
			if (*votes[i]>*votes[selected]) {
				selected=i;
			} // if 
		} // for 

		solution_record=new FeatureTerm((char *)0,m_ontology->get_sort("problem-prediction"),1,
										"solution",new FeatureTerm(solutions[selected]));
		return solution_record;
	}
	*/

	// Instead of voting, find the JER with highest confidence and return it:
	{
		FeatureTerm *best_JER=0;
		float best_JER_c=0.0f;

		for(i=0;i<JERs.Length();i++) {
			if (best_JER==0 || best_JER_c<*JER_Cs[i]) {
				best_JER = JERs[i];
				best_JER_c = *JER_Cs[i];
			} // if 
		} // for 

		return new FeatureTerm(best_JER);
	}

} /* AW_NOOSLearnerBrainSocial::solve_problem_IBA_convener_social */ 


void AW_NOOSLearnerBrainSocial::solve_problem_IBA_other_social(FeatureTerm *problem,Sort *sort,Symbol *my_name,Symbol *convener_name,bool test)
{
	AW_Message *m;
	FeatureTerm *m_content;
	FeatureTerm *my_prediction=0;
	bool end;
	List<FeatureTerm> self_CAs_historic,self_CEs_historic;

	write_debug_report("[%s]: IBA other started (convened by %s).\n",my_name->get(),convener_name->get());


	/* Produce initial prediction: */ 
	{
		FeatureTerm *op;
		Sort *sort=get_case_sort(m_ontology,problem->getSort());
		char *s;

		my_prediction = build_single_jer(problem,sort,my_name);
		s=my_prediction->toStringNOOS(m_memory);

		/* Send back the solution: */ 
		op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
						   "receiver",new FeatureTerm(0,new Symbol(convener_name),m_ontology),
						   "content",new FeatureTerm(0,new Symbol(s),m_ontology));
		enqueue_operator(op);
		delete []s;	
	}


	/* Wait till I have the token or until termination message: */ 
	end=false;
	do{
		wait_message();
		m=get_message();
		m_content=FeatureTerm::fromStringNOOS(m->content->get(),m_memory,m_ontology);
		
		/* Terminate protocol: */ 
		if (m_content->getSort()==m_ontology->get_sort("reset-iba") ||
			m_content->getSort()==m_ontology->get_sort("reset-test-iba")) {
			FeatureTerm *op;

			/* Appply retention strategy: */ 
			if (m_content->getSort()==m_ontology->get_sort("reset-iba"))
				retain_cases(&received_cases_IBA2A,m_amal2_retention_strategy);

			received_cases_IBA2A.Delete();
			/* Send back a confirmation: */ 
			op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
							   "receiver",new FeatureTerm(0,new Symbol(m->sender),m_ontology),
							   "content",new FeatureTerm(0,new Symbol("(define (any))"),m_ontology));
			enqueue_operator(op);

			write_debug_report("[%s]: IBA protocol terminated.\n",my_name->get());			

			end=true;
		} /* if */ 
		
		/* Examine jutifications: */ 
		if (m_content->getSort()==m_ontology->get_sort("request-examination-message")) {
			FeatureTerm *op;
			FeatureTerm *problem;
			FeatureTerm *JERs,*JER;
			FeatureTerm *XERs;
			char *s;

			JERs=m_content->featureValue("prediction");
			problem=m_content->featureValue("problem");

			if (JERs==0 || problem==0) write_debug_report("em: ERROR 1\n");

			/* Examine the JER: */ 
			{
				Sort *sort=get_case_sort(m_ontology,problem->getSort());
				if (sort==0) write_debug_report("em: ERROR 2\n");

				XERs=FeatureTerm::SetFeatureTerm((Symbol *)0);

				if (JERs->isFeatureTerm()) {
					XERs->addSetValue(examine_JER(JERs,sort));
				} else {
					List<FeatureTerm> *l;
					l=JERs->set_values_quick();
					l->Rewind();
					while(l->Iterate(JER)) {
						XERs->addSetValue(examine_JER(JER,sort));
					} /* while */ 
				} /* if */ 

				s=XERs->toStringNOOS(m_memory);
				delete XERs;
			}

			/* Send back the solution: */ 
			op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
							   "receiver",new FeatureTerm(0,new Symbol(m->sender),m_ontology),
							   "content",new FeatureTerm(0,new Symbol(s),m_ontology));
			enqueue_operator(op);
			delete []s;

			delete JERs;
			delete problem;
		} /* if */ 


		/* Receives a counterargument: */ 
		if (m_content->getSort()==m_ontology->get_sort("counterargument-message")) {
			FeatureTerm *op;
			char *s;

			write_debug_report("[%s]: received a counterargument.\n",my_name->get());	

			s=0;
			/* Consider whether to change my prediction: */ 
			if (local_confidence(m_content->featureValueQuick("counterargument"),sort) > 
				local_confidence(my_prediction,sort)) {

				write_debug_report("[%s]: The counterargument of the other agent has convinced me.\n",my_name->get());

				delete my_prediction;
				my_prediction=0;
				my_prediction=m_content->featureValue("counterargument");
				
				/* change my current prediction: */ 
				s=my_prediction->toStringNOOS(m_memory);
			} /* if */ 
			

			/* Send back a confirmation: */ 
			op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
							   "receiver",new FeatureTerm(0,new Symbol(m->sender),m_ontology),
							   "content",new FeatureTerm(0,new Symbol(s),m_ontology));
			if (s!=0) delete []s;
			enqueue_operator(op);
		} /* if */ 


		/* Receives a counterexample: */ 
		if (m_content->getSort()==m_ontology->get_sort("counterexample-message")) {
			FeatureTerm *tmp;

			write_debug_report("[%s]: received a counterexample.\n",my_name->get());	
			
			/* Retain the new case: */ 
			tmp=m_content->featureValue("counterexample");
			write_debug_report("[%s]: learnt case %s\n",m->receiver->get(),tmp->getName()->get());
			received_cases_IBA2A.Add(tmp);

			/* Generate a new prediction: */ 
			{
				FeatureTerm *op,*old_prediction;
				Sort *sort=get_case_sort(m_ontology,problem->getSort());
				char *s;

				old_prediction=my_prediction;
				my_prediction = build_single_jer(problem,sort,my_name);
				s=my_prediction->toStringNOOS(m_memory);

				/* Check if anyone has changed opinion, for logging purposes: */ 
				if (old_prediction!=0) {
					FeatureTerm *old_sol,*new_sol;
					old_sol=old_prediction->featureValueQuick("solution");
					new_sol=my_prediction->featureValueQuick("solution");

					if (!(*old_sol==*new_sol)) {
						char *s1,*s2;
						s1=old_prediction->featureValueQuick("solution")->toStringNOOS(m_memory);
						s2=my_prediction->featureValueQuick("solution")->toStringNOOS(m_memory);
						write_debug_report("[%s]: I changed my mind because of a counterexample (%s to %s).\n",
											my_name->get(),
											s1,s2);
						delete []s1;
						delete []s2;
					} // if 
				}

				if (old_prediction!=0) delete old_prediction;

				/* Send back the solution: */ 
				op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
								   "receiver",new FeatureTerm(0,new Symbol(convener_name),m_ontology),
								   "content",new FeatureTerm(0,new Symbol(s),m_ontology));
				enqueue_operator(op);
				delete []s;	
			}
		} /* if */ 


		/* The agent owns the token: */ 
		if (m_content->getSort()==m_ontology->get_sort("token-iba-message")) {
			FeatureTerm *op;
			FeatureTerm *counterargument;
			FeatureTerm *f;
			char *s;

			write_debug_report("[%s]: I have the token -----------------------------------\n",my_name->get());
			{
				List<FeatureTerm> JERs;
				List<float> JER_Cs;

				{
					List<FeatureTerm> *l;
					FeatureTerm *JER,*C;

					l=m_content->featureValueQuick("arguments")->set_values();

					l->Rewind();
					while(l->Iterate(f)) {
						JER=f->featureValue("prediction");
						C=f->featureValue("confidence");
						JERs.Add(JER);
						JER_Cs.Add(new float(C->getFloat()));
						delete C;
					} /* while */ 

					delete l;
				}
				counterargument=IBA_generate_counterargument(problem,&JERs,&JER_Cs,my_name,&self_CAs_historic,&self_CEs_historic);
				
				if (counterargument!=0) {
					/* If it is a counterargument, then consider if changing my current prediction: */ 
					if (counterargument->getSort()==m_ontology->get_sort("counterargument-message")) {
						if (local_confidence(counterargument->featureValueQuick("counterargument"),sort) > 
							local_confidence(my_prediction,sort)) {
							FeatureTerm *tmp;
							/* change my current prediction: */ 
							write_debug_report("[%s]: I change my current prediction.\n",my_name->get());

							tmp=FeatureTerm::SetFeatureTerm();
							tmp->addSetValue(counterargument);
							tmp->addSetValue(counterargument->featureValue("counterargument"));
							counterargument=tmp;
						} /* if */ 
					} /* if */ 
				} /* if */ 
			}

			if (counterargument!=0) {
				s=counterargument->toStringNOOS(m_memory);
				delete counterargument;
			} else {
				s=0;
			} /* if */ 

			/* Send back a confirmation: */ 
			op=new FeatureTerm((char *)0,m_ontology->get_sort("send-operator"),2,
							   "receiver",new FeatureTerm(0,new Symbol(m->sender),m_ontology),
							   "content",new FeatureTerm(0,new Symbol(s),m_ontology));
			if (s!=0) delete []s;
			enqueue_operator(op);
		} /* if */ 

		delete m_content;
		delete m;
	}while(!end);

	if (my_prediction!=0) delete my_prediction;

} /* AW_NOOSLearnerBrainSocial::solve_problem_IBA_other_social */ 


